import requests
from io import StringIO
import random
import math

TOTAL = 150       # 总数据的数量
TEST_SIZE = 50    # 测试数据的数量
TRAIN_SIZE = 100  # 训练数据的数量
N = 4             # 特征数据的数量（维数）
KN = 15           # K的最大取值

class Distance:
    def __init__(self, data, train_set_label):
        self.data = data
        self.train_set_label = train_set_label

class Iris:
    def __init__(self, data, flower_type, label):
        self.data = data
        self.type = flower_type
        self.label = label

def label_abc(flower_type):
    if "setosa" in flower_type:
        return 'A'
    elif "versicolor" in flower_type:
        return 'B'
    elif "virginica" in flower_type:
        return 'C'
    else:
        return '0'


def make_rand(iris_list):
    random.shuffle(iris_list)

def open_data_file(path):
    temp = []
    with open(path, 'r') as file:
        for line in file:
            values = line.strip().split(',')
            if len(values) == N + 1:  # 检查是否有足够的数据项
                data = list(map(float, values[:N]))
                flower_type = values[-1]
                label = label_abc(flower_type)
                temp.append(Iris(data, flower_type, label))
    make_rand(temp)
    return temp

def print_data(test_set, train_set):
    print("\n设置标签 -> 打乱 -> 按比例分割\n")
    print("数据如下：\n\n")
    print("testSet:\n")
    for item in test_set:
        print(" ".join(f"{val:.2f}" for val in item.data), item.label)
    print("\n\ntrainSet:\n")
    for item in train_set:
        print(" ".join(f"{val:.2f}" for val in item.data), item.label)

def load_data(temp):
    test_set = temp[:TEST_SIZE]
    train_set = temp[TEST_SIZE:]
    return test_set, train_set

def euclidean_distance(d1, d2):
    return math.sqrt(sum((x - y) ** 2 for x, y in zip(d1, d2)))

def compare_label(a, b, c):
    if a > b and a > c:
        return 'A'
    elif b > a and b > c:
        return 'B'
    elif c > a and c > b:
        return 'C'
    return '0'

def count_label(distance_list, k, test_set_label):
    sum_a, sum_b, sum_c = 0, 0, 0
    for i in range(k):
        label = distance_list[i].train_set_label
        if label == 'A':
            sum_a += 1
        elif label == 'B':
            sum_b += 1
        elif label == 'C':
            sum_c += 1

    if compare_label(sum_a, sum_b, sum_c) == test_set_label:
        return 1
    return 0

def main():
    temp = open_data_file("iris.data")
    test_set, train_set = load_data(temp)
    print_data(test_set, train_set)

    for k in range(1, KN + 1):
        count = 0
        print(f"\nCheck P: K = {k}\n")
        for test_item in test_set:
            distance_list = [
                Distance(euclidean_distance(test_item.data, train_item.data), train_item.label)
                for train_item in train_set
            ]
            distance_list.sort(key=lambda x: x.data)
            count += count_label(distance_list, k, test_item.label)

        print(f"K = {k}     P = {100.0 * count / TEST_SIZE:.2f}%")

if __name__ == "__main__":
    main()
